import Train from './Train';
import { ComboType, UIConfig } from './UIConfig';

/**
 * 方块组合
 */
export default class ComboModel {

    public xySet: Train[]; // 坐标集

    public sameXY: Train; // 共同坐标

    public type: ComboType; // 组合类型

    constructor(list: Train[]) {
        this.xySet = list;
        this.updateType();
    }

    /**
     * 更新类型
     */
    private updateType() {
        let up = 0;
        let down = 0;
        let left = 0;
        let right = 0;
        let xy = this.sameXY ? this.sameXY : this.xySet[0]; // 关键坐标
        // 收集数量
        for (let i = 0; i < this.xySet.length; i++) {
            if (this.xySet[i].isSame(xy)) continue; // 同一个坐标时跳过
            // 判断位置
            if (this.xySet[i].x === xy.x) {
                if (this.xySet[i].y > xy.y) up++;
                else down++;
            } else {
                if (this.xySet[i].x < xy.x) left++;
                else right++;
            }
        }
        // 判断类型
        if (up === 0 && down === 0) this.type = ComboType.Horizontal;
        else if (left === 0 && right === 0) this.type = ComboType.Vertical;
        else if (up > 0 && down > 0 && left > 0 && right > 0) this.type = ComboType.Cross;
        else if ((up > 0 && down === 0 && left === 0 && right > 0) ||
            (up > 0 && down === 0 && left > 0 && right === 0) ||
            (up === 0 && down > 0 && left === 0 && right > 0) ||
            (up === 0 && down > 0 && left > 0 && right === 0)) {
            this.type = ComboType.LShape;
        } else if ((up === 0 && down > 0 && left > 0 && right > 0) ||
            (up > 0 && down === 0 && left > 0 && right > 0) ||
            (up > 0 && down > 0 && left === 0 && right > 0) ||
            (up > 0 && down > 0 && left > 0 && right === 0)) {
            this.type = ComboType.TShape;
        }
    }

    /**
     * 组合是否包含坐标集中的任意一个，有得返回对应坐标
     * @param list 查询坐标集
     */
    public include(list: Train[]): Train {
        for (let i = 0; i < this.xySet.length; i++) {
            for (let j = 0; j < list.length; j++) {
                if (this.xySet[i].isSame(list[j])) return list[j];
            }
        }
        return null;
    }

    /**
     * 合并组合
     * @param list 坐标集
     * @param xy 共同坐标
     */
    public merge(list: Train[], xy: Train) {
        for (let i = 0; i < list.length; i++) {
            if (!list[i].isSame(xy))
                this.xySet.push(list[i]);
        }
        this.sameXY = xy;
        this.updateType();
    }

    /**
    * 获取可消除的组合
    */
    static getCombos(typeMap: number[][]): ComboModel[] {
        let combos: ComboModel[] = [];
        // 逐行检测
        for (let r = 0; r < UIConfig.ROW; r++) {
            let count: number = 0;
            let type: number = -1;
            for (let c = 0; c < UIConfig.COL; c++) {
                if (c === 0) {
                    count = 1; // 连续计数
                    type = typeMap[c][r]; // 保存类型
                } else {
                    if (typeMap[c][r] && typeMap[c][r] === type) {
                        // 类型相同
                        count++;
                        // 到最后一个了，是不是有 3 个以上连续
                        if (c === UIConfig.COL - 1 && count >= 3) {
                            let list = [];
                            for (let i = 0; i < count; i++) {
                                list.push(new Train(c - i, r));
                            }
                            combos.push(new ComboModel(list));
                        }
                    } else {
                        // 类型不同
                        if (count >= 3) {
                            // 已累积 3 个
                            let list = [];
                            for (let i = 0; i < count; i++) {
                                list.push(new Train(c - 1 - i, r));
                            }
                            combos.push(new ComboModel(list));
                        }
                        // 重置
                        count = 1;
                        type = typeMap[c][r];
                    }
                }
            }
        }
        // 逐列检测
        for (let c = 0; c < UIConfig.COL; c++) {
            let count: number = 0;
            let type: number = -1;
            for (let r = 0; r < UIConfig.ROW; r++) {
                if (r === 0) {
                    count = 1;
                    type = typeMap[c][r];
                } else {
                    if (typeMap[c][r] && typeMap[c][r] === type) {
                        count++;
                        if (r === UIConfig.ROW - 1 && count >= 3) {
                            let list = [];
                            for (let i = 0; i < count; i++) {
                                list.push(new Train(c, r - i));
                            }
                            // 是否可以和已有组合合并
                            let hasMerge = false;
                            for (let i = 0; i < combos.length; i++) {
                                let common = combos[i].include(list);
                                if (common) {
                                    combos[i].merge(list, common);
                                    hasMerge = true;
                                    break;
                                }
                            }
                            if (!hasMerge) combos.push(new ComboModel(list));
                        }
                    } else {
                        if (count >= 3) {
                            let list = [];
                            for (let i = 0; i < count; i++) {
                                list.push(new Train(c, r - 1 - i));
                            }
                            // 是否可以和已有组合合并
                            let hasMerge = false;
                            for (let i = 0; i < combos.length; i++) {
                                let common = combos[i].include(list);
                                if (common) {
                                    combos[i].merge(list, common);
                                    hasMerge = true;
                                    break;
                                }
                            }
                            if (!hasMerge) combos.push(new ComboModel(list));
                        }
                        count = 1;
                        type = typeMap[c][r];
                    }
                }
            }
        }
        return combos;
    }
}
